#include "CStateLogin.h"

#include "CStateMainMenu.h"
#include "COverlord.h"
#include "CMinion.h"
#include "CNetworkManager.h"
#include "CNetworkIO.h"

CStateLogin::CStateLogin(CGameManager * mgr) : CState(mgr)
{
}

CStateLogin::~CStateLogin()
{
  parent->remove();
}


void CStateLogin::init()
{
  parent = env->addTab (rect<s32>(0, 0, 800, 600));

  IGUIImage* background = env->addImage( rect<s32>(0,0,SCREEN_W, SCREEN_H), parent);
  background->setImage(driver->getTexture("front2.png"));
  background->setScaleImage(true);

  IGUIImage* background2 = env->addImage( rect<s32>(0,0,800,40), parent);
  background2->setImage(driver->getTexture("baseline.jpg"));
  background2->setScaleImage(true);

  IGUIImage* background3 = env->addImage( rect<s32>(0,560,800,600), parent);
  background3->setImage(driver->getTexture("lowbaseline.jpg"));
  background3->setScaleImage(true);
}

void CStateLogin::close()
{
  parent->remove();
}

void CStateLogin::run()
{
  driver->beginScene(true, true, SColor(255,0,0,0));
  smgr->drawAll();

  env->drawAll();

}

void CStateLogin::enable()
{
  parent->setVisible(true);
}

void CStateLogin::disable()
{
  parent->setVisible(false);
}

//! Event Receiving Methods

void CStateLogin::OnServerPacketReceived(Packet *packet)
{
  switch (packet->data[0])
  {
    case ID_LON_LOGIN_FAIL:
      env->addMessageBox(L"Error",L"Invalid username or password.");
      break;

    case ID_LON_LOGIN_SUCESS:
      loginSucess(new BitStream(packet->data, packet->length, false));
      mgr->pushState(new CStateMainMenu(mgr));
      break;

    case ID_LON_CREATE_ACCOUNT:
      ackCreateAccount(new BitStream(packet->data, packet->length, false));
      break;

    /// Default RakNet Messages
    case ID_CONNECTION_REQUEST_ACCEPTED:
      showLoginPanel();
      break;

    case ID_CONNECTION_ATTEMPT_FAILED:
      env->addMessageBox(L"Error",L"Failed to connect to server.")->setID(MSG_DISCONNECT);
      break;

    case ID_NO_FREE_INCOMING_CONNECTIONS:
      env->addMessageBox(L"Error",L"The server is full.")->setID(MSG_DISCONNECT);
      break;

    case ID_DISCONNECTION_NOTIFICATION:
      env->addMessageBox(L"Error",L"You have been disconnected.")->setID(MSG_DISCONNECT);
      break;

    case ID_CONNECTION_LOST:
      env->addMessageBox(L"Error",L"Connection Lost.")->setID(MSG_DISCONNECT);
      break;

    default:
      std::cout << "Message with identifier " << int (packet->data[0]) << " has arrived.\n" << std::endl;
      break;
  }
}

void CStateLogin::OnClientPacketReceived(Packet *packet)
{
  cout << "ERROR: This state should not receive client's packets" << endl;
}

//! Called when a GUI button
bool CStateLogin::OnButtonClick(s32 id)
{
  switch (id)
  {
    case BTN_LOGIN:
      login();
      return true;
      break;

    case BTN_CREATE_ACCOUNT:
      showCreateAccountWindow();
      break;

    case BTN_CA_OK:
      requestCreateAccount();
      break;

    case BTN_CA_CANCEL:
      caWindow->remove();
      break;

    case BTN_POPSTATE:
      //! Exit game
      mgr->popState();
      return true;
      break;

  }
  return false;
}

bool CStateLogin::OnGUIEvent(const SEvent& event)
{
  s32 id = event.GUIEvent.Caller->getID();

  switch(event.GUIEvent.EventType)
  {
    case EGET_MESSAGEBOX_OK :
      if ( id == MSG_DISCONNECT )
      {
        mgr->popState();
        return true;
      }
      break;

    case EGET_EDITBOX_ENTER :
      if ( id == TXT_PASSWORD )
      {
        login();
      }
    default:
      return false;
      break;
  }

  return false;
}

void CStateLogin::showLoginPanel()
{
  // Control variables for ui (left, right, up, down, temp var a, b )
  short lf, rt, up, dn, a, b;

  //! The Login Panel
  a = 25; // This means items heigh
  b = 10; // This means items padding

  lf = 275;
  rt = 525;
  up = 300;
  dn = 470;

  // Panel background
  /*
  IGUIStaticText * bg;
  bg = env->addStaticText(L"", rect<s32>(lf, up, rt, dn), false, true, parent, -1, true);
  bg->setBackgroundColor(SColor(128, 255, 255, 255 ));
  */

  IGUIImage* bg= env->addImage( rect<s32>(lf, up, rt, dn), parent);
  bg->setImage(driver->getTexture("frame.png"));
  bg->setScaleImage(true);
  bg->setUseAlphaChannel(true);

  IGUIStaticText *temp;
  // Login Box
  up += b + 10;
  dn = up + a;
  lf = 295;
  rt = lf + 80;
  temp = env->addStaticText(L"Username: ", rect<s32>(lf, up, rt, dn), false, true, parent);
  temp->setOverrideColor(SColor(255, 255, 255, 255));

  lf += 80;
  rt = 505;
  txtUsername = env->addEditBox(L"", rect<s32>(lf, up, rt, dn), true, parent, -1);

  // Password Box
  up += a + b;
  dn = up + a;
  lf = 295;
  rt = lf + 80;
  temp = env->addStaticText(L"Password: ", rect<s32>(lf, up, rt, dn), false, true, parent);
  temp->setOverrideColor(SColor(255, 255, 255, 255));

  lf += 80;
  rt = 505;
  txtPassword = env->addEditBox(L"", rect<s32>(lf, up, rt, dn), true, parent, TXT_PASSWORD);
  txtPassword->setPasswordBox(true);

  up += a + b;
  dn = up + a;

  // create a button
  lf = 295;
  rt = 395;
  env->addButton(rect<s32>(lf, up, rt, dn), parent, BTN_LOGIN    , L"Login");


  lf = 405;
  rt = 505;
  env->addButton(rect<s32>(lf, up, rt, dn), parent, BTN_POPSTATE , L"Quit");

  up += a + b;
  dn = up + a;
  lf = 295;
  rt = 505;
  env->addButton(rect<s32>(lf, up, rt, dn), parent, BTN_CREATE_ACCOUNT, L"Create Account");
}


void CStateLogin::showCreateAccountWindow()
{
  caWindow = env->addWindow(rect <s32> (100, 100 ,400 ,400), false, L"Create Account", parent);

  s32 d = 30;
  s32 h = 25;
  s32 p = h+15;
  s32 tl = 25; s32 tr = 160;
  s32 el = 170; s32 er = 270;
  // Temp
  env->addStaticText(L"Username: ", rect<s32>(tl, d, tr, d+h), false, false, caWindow);
  txtCaUsername = env->addEditBox(L"", rect<s32>(el, d, er, d+h), true, caWindow);

  d+=p;

  env->addStaticText(L"Password: ", rect<s32>(tl, d, tr, d+h), false, false, caWindow);
  txtCaPassword1 = env->addEditBox(L"", rect<s32>(el, d, er, d+h), true, caWindow);
  txtCaPassword1->setPasswordBox(true);

  d+=p;
  env->addStaticText(L"Confirm Password: ", rect<s32>(tl, d, tr, d+h), false, false, caWindow);
  txtCaPassword2 = env->addEditBox(L"", rect<s32>(el, d, er, d+h), true, caWindow);
  txtCaPassword2->setPasswordBox(true);

  d+=p;

  env->addStaticText(L"Overlord Details: ", rect<s32>(tl, d, tr, d+h), false, false, caWindow);
  d+=h;
  env->addStaticText(L"In-Game Name: ", rect<s32>(tl, d, tr, d+h), false, false, caWindow);
  txtCaName = env->addEditBox(L"", rect<s32>(el, d, er, d+h), true, caWindow);

  d+=p;
  env->addStaticText(L"Class: ", rect<s32>(tl, d, tr, d+h), false, false, caWindow);
  comOverlordType = env->addComboBox(rect<s32>(el, d, er, d+h), caWindow);

  for ( u8 i=0; i<OLT_COUNT; i++ )
  {
    stringw typeName;
    switch (i)
    {
      case OLT_ATTACKER: typeName = "Attacker"; break;
      case OLT_DEFENDER: typeName = "Defender"; break;
      case OLT_CASTER:   typeName = "Caster"; break;
    }
    comOverlordType->addItem(typeName.c_str());
  }
  d+=p;

  env->addButton(rect<s32>(25, d, 125, d+h), caWindow, BTN_CA_OK, L"Ok");
  env->addButton(rect<s32>(135, d, 235, d+h), caWindow, BTN_CA_CANCEL, L"Cancel");
/*
  env->addStaticText(L"Name of the new Minion: ", rect<s32>(10, 30, 190, 50), false, false, minionWindow);
  txtMinionName = env->addEditBox(L"", rect<s32>(10, 60, 210, 80), true, minionWindow);


  comMinionType = env->addComboBox(rect<s32>(10, 90, 190, 110), minionWindow)
  for (u32 i=0; i<vMinionBase.size(); i++)
  {
    comMinionType->addItem(vMinionBase[i].typeName.c_str());
  }
*/
  //env->addButton(rect<s32>(10, 120, 95, 140), minionWindow, BTN_CA_OK, L"Ok");
  //env->addButton(rect<s32>(105, 120, 190, 140), minionWindow, BTN_CA_CANCEL, L"Cancel");
}


//! Called when login button is pressed
void CStateLogin::login()
{
  //! Login into the server
  if ( wcslen(txtUsername->getText()) == 0 )
  {
    env->addMessageBox(L"Error",L"Please enter your username.");
    return;
  }

  BitStream bs;

  // Convert the text into binary data for bitstream transfer
  wchar_t *text = const_cast <wchar_t*> (txtUsername->getText());
  char *data =  (char*) text;

  // note that length need to be +1 for the null terminator
  unsigned short len = ( wcslen(text) + 1 ) * 2;

  // Write the message ID
  unsigned char msgId = ID_LON_LOGIN;
  bs.Write(msgId);

  // Write the length of the username
  bs.Write( len );

  // Write the username text
  bs.Write(data, len);


  // Convert the text into binary data for bitstream transfer
  text = const_cast <wchar_t*> (txtPassword->getText());
  data =  (char*) text;

  // note that length need to be +1 for the null terminator
  len = ( wcslen(text) + 1 ) * 2;

  // Write the length of the password
  bs.Write( len );

  // Write the length of the password
  bs.Write(data, len );

  // Send the packet
  mgr->getNetworkManager()->sendPacket(&bs);
}

void CStateLogin::loginSucess(BitStream *bs)
{
  stringw login;
  stringw name;
  u8 type;
  u16 title;
  u16 fame;
  u8 msgId;

  bs->Read(msgId);

  COverlord *player = new COverlord();
  player->netRead(*bs);
  mgr->setPlayer(player);

  //! Minions details
  u32 count;
  bs->Read(count);

  for ( u32 i=0; i<count; i++ )
  {
    u32 minion_id;
    minionStats stats;
    bs->Read(minion_id);
    stats.netRead(*bs);
    cout << "Minion Loaded: " << endl;
    stats.displayStats();

    CMinion *minion = new CMinion(stats);
    minion->set_minion_id(minion_id);
    mgr->getPlayer()->addMinion(minion);
  }

  delete bs;
}

void CStateLogin::requestCreateAccount()
{
  // Simple Vadilation
  if ( wcslen(txtCaUsername->getText()) < 3)
  {
    env->addMessageBox(L"Error",L"Username must have at least 3 characters.");
    return;
  }

  stringw p1(txtCaPassword1->getText());
  stringw p2(txtCaPassword1->getText());

  if ( p1 != p2 )
  {
    env->addMessageBox(L"Error",L"Your password fields does not match.");
    return;
  }

  BitStream bs;

  // Write the message ID
  bs.Write(u8(ID_LON_CREATE_ACCOUNT));

  CNetworkIO::writeWcs(bs, txtCaUsername->getText());
  CNetworkIO::writeWcs(bs, txtCaPassword1->getText());
  CNetworkIO::writeWcs(bs, txtCaName->getText());

  u8 type = comOverlordType->getSelected();
  bs.Write(type);

  mgr->getNetworkManager()->sendPacket(&bs);
}

void CStateLogin::ackCreateAccount(BitStream *bs)
{
  bool sucess;
  u8 msgId;
  bs->Read(msgId);
  bs->Read(sucess);

  if ( sucess )
  {
    caWindow->remove();
    env->addMessageBox(L"Sucess", L"Account has been created sucessfully.");
  }
  else
  {
    env->addMessageBox(L"Error", L"Username is already in use.");
  }
}
